#include "nr_channel_manager.h"
#include "nr_object_manager.h"

nr_channel_manager::nr_channel_manager(nr_device_item_manager& item_manager)
    : m_item_manager(item_manager)
{
}

nr_channel_manager::~nr_channel_manager()
{
}

nr_error_t nr_channel_manager::create_input_channel(const nr_device_id_t& device_id, nr_channel_input **p_channel_input)
{
    Q_ASSERT(false);
    return NR_ERROR_NOT_IMPLEMENTED;
}

nr_error_t nr_channel_manager::create_output_channel(const nr_device_id_t& device_id, 
    nr_channel_output_delegate& data_delegate,
    nr_channel_output *&p_channel_output)
{
    nr_error_t status = NR_ERROR_NONE;
    nr_channel_input *input_channel = NULL;
    nr_device_item* device_item = NULL;
    nr_channel_output *output_channel = NULL;

    p_channel_output = NULL;

    // Existed, add one more output channels reference for the input channel
    nr_input_channels::iterator it = m_input_channels.find(device_id);
    if (it != m_input_channels.end())
    {
        // Create a new output channel and 
        input_channel = it.value();
        Q_ASSERT(input_channel);

        // Create a new output channel
        output_channel = new nr_channel_output(data_delegate, *input_channel);
        output_channel->device_id() = device_id;
        
        // Attach it to the input channel
        status = input_channel->add_output_channel(output_channel);
        Q_ASSERT(NR_SUCCEED(status));
    }
    else
    {
        // Find in the device items whether the device id exist
        device_item = m_item_manager.find_device_item_by_id(device_id);
        if (device_item == NULL) // Not found
            return NR_ERROR_DEVICE_NOT_FOUND;
        
        // Init the device item if the device is empty
        if (device_item->device() == NULL)
        {
            status  = device_item->init_device();
            if (NR_FAILED(status))
                return status;
        }

        Q_ASSERT(device_item->device());

        // Create a new input channel
        input_channel = new nr_channel_input;
        input_channel->device_id() = device_id;
        input_channel->attach_device_item(device_item);
        
        // Create a new output channel
        output_channel = new nr_channel_output(data_delegate, *input_channel);
        output_channel->device_id() = device_id;

        // Attach it to the input channel
        status = input_channel->add_output_channel(output_channel);
        Q_ASSERT(NR_SUCCEED(status));

        // Add to the input channel list and set device's delegate
        m_input_channels.insert(device_id, input_channel);
        // device_item->device()->set_delegate(input_channel);
    }
    
    // Set to the output channel
    p_channel_output = output_channel;

    return NR_ERROR_NONE;
}

nr_error_t nr_channel_manager::destroy_output_channel(nr_channel_output *channel_output)
{
    if (channel_output == NULL)
        return NR_ERROR_NOT_VALID_PARAMETER;

    // First find the input channel
    nr_input_channels::iterator it = m_input_channels.find(channel_output->device_id());
    if (it == m_input_channels.end()) // Not found
        return NR_ERROR_CHANNEL_NOT_FOUND;
    
    // Find the output channel in the input channel
    nr_channel_input *input_channel = it.value();
    Q_ASSERT(input_channel);

    // Destroy the output channel and remove it from the input channel list
    // When destroying the output channel, the output channel will try to stop the input channel
    channel_output->stop();
    input_channel->remove_output_channel(channel_output);

    delete channel_output;
    
    // Destroy the input channel, if it is empty
    if (input_channel->is_empty())
    {
        m_input_channels.erase(it);
        delete input_channel;
    }
        
    return NR_ERROR_NONE;
}


